package cn.boodqian.airreport;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import com.google.gson.Gson;

import cn.boodqian.util.Log;

public class AirData {
	public int version = 0;
	private int length = 0;
	private Date time = null;
	private HashMap<String, ArrayList<Float>> data = new HashMap<String, ArrayList<Float>>();
	
	public static final long MS_PER_HOUR = 60*60*1000;
	public static final int MAX_HOURS = 24;//*30+24; // A month
	
	
	public void addData(String name, ArrayList<Float> data) {
		assert(name!=null && data!=null);
		if(length>0)
			assert(length==data.size());
		else
			length = data.size();
		this.data.put(name, data);
	}
	
	public int getLength() {
		return length;
	}
	
	public List<Float> getData(String name) {
		if(!data.containsKey(name)) return null;
		return  Collections.unmodifiableList(data.get(name));
	}
	public void setTime(Date t) {
		assert(t!=null);
		time = t;
	}
	public Date getTime() {
		return time;
	}
	
	public void merge(AirData new_data) {
		if(new_data==null || new_data.length == 0) return;
		
		Log.i("enter");
		if(Log.isLoggable(Log.DEBUG)) Log.d("old data=" + new Gson().toJson(this));
		if(Log.isLoggable(Log.DEBUG)) Log.d("new data=" + new Gson().toJson(new_data));
		long currentMaxTime = time.getTime()/MS_PER_HOUR;
		long currentMinTime =  currentMaxTime - (length-1);
		
		long maxTime = new_data.time.getTime()/MS_PER_HOUR;
		long minTime =  maxTime - (new_data.length-1);
		
		if(Log.isLoggable(Log.DEBUG)) Log.d(String.format("%d-%d %d-%d", currentMinTime, currentMaxTime, minTime, maxTime));
		
		// Check having the same set of data
		assert(this.data.size()==new_data.data.size());
		for(String name:this.data.keySet()) {
			assert(new_data.data.containsKey(name));
		}
		
		// Expand the current list to include both time span
		if(maxTime > currentMaxTime) {
			for(long t = currentMaxTime+1;t<=maxTime;t++) {
				for(ArrayList<Float> list:data.values()) {
					list.add(0f);
				}
				this.length++;
			}
			currentMaxTime = maxTime;
		}
		else if(minTime < currentMinTime) {
			for(long t = minTime;t<currentMinTime;t++) {
				for(ArrayList<Float> list:data.values()) {
					list.add(0, 0f);
				}
				this.length++;
			}
			currentMinTime = minTime;
		}
		time.setTime(currentMaxTime*MS_PER_HOUR);
		if(Log.isLoggable(Log.DEBUG)) Log.d("merged data1=" + new Gson().toJson(this));
		
		// Replace with new value if new value is not 0
		for(String name:this.data.keySet()) {
			Log.i("replacing "+name);
			for(int i=0;i<new_data.getLength();i++) {
				long t = minTime + i;
				int index = (int) (t - currentMinTime);

				if(new_data.getData(name).get(i).compareTo(0f) != 0) {
					Float v = (Float) new_data.getData(name).get(i);
					this.data.get(name).set(index, v);
				}
			}
		}
		
		if(Log.isLoggable(Log.DEBUG)) Log.d("merged data2=" + new Gson().toJson(this));
		
		// Cut the data exceed the max capacity MAX_HOURS
		if(this.length > MAX_HOURS) {
			if(Log.isLoggable(Log.INFO)) Log.i(String.format("%d exceeds max capacity %d, cutting off", length, MAX_HOURS));
			for(String name:this.data.keySet()) {
				this.data.get(name).subList(0, length-MAX_HOURS).clear();
			}
			length = MAX_HOURS;
		}
		
		Log.i("exit");
	}
}
